<?php

namespace App\Models\Trip\OrderPay\Repositories;

use App\Events\Plane\PlaneOrder\PlaneOrderStateUpdatedEvent;
use App\Events\Train\TrainOrder\TrainOrderStateUpdatedEvent;
use App\Exceptions\OrderPay\BusinessMustBeRefundException;
use App\Exceptions\OrderPay\NotSupportedPayBusinessException;
use App\Exceptions\OrderPay\PayInfoNotFoundException;
use App\Exceptions\Plane\Order\PlaneOrderStockNotEnoughException;
use App\Exceptions\Plane\Order\PlaneTicketFailedException;
use App\Exceptions\TooManyActionException;
use App\Exceptions\Train\Order\TrainSnapEditPayErrorException;
use App\Exceptions\Train\Order\TrainTicketFailedException;
use App\Jobs\Plane\PlaneOrder\ProcessAfterPlaneOrderPaid;
use App\Jobs\Train\TrainOrder\ProcessAfterTrainOrderPaid;
use App\Models\Common\Channel\Channel;
use App\Models\Plane\PlaneOrders\PlaneOrder;
use App\Models\Plane\PlaneOrders\Repositories\Interfaces\PlaneOrderRepositoryInterface;
use App\Models\Scenic\Order\ScenicOrderGoods;
use App\Models\Scenic\ScenicOrder;
use App\Models\Scenic\ScenicSpotGoods;
use App\Models\Train\TrainOrders\Repositories\Interfaces\TrainOrdersRepositoryInterface;
use App\Models\Train\TrainOrders\TrainOrder;
use App\Models\Trip\OrderPay\OrderPay;
use App\Models\Trip\OrderPay\OrderPayDetail;
use App\Models\Trip\OrderPay\Repositories\Interfaces\OrderPayDetailsRepositoryInterface;
use App\Models\Trip\OrderPay\Repositories\Interfaces\OrderPayRepositoryInterface;
use App\Models\Trip\OrderPay\SnapTaskEditPay;
use App\Models\Trip\RefundNeedPay\RefundNeedPay;
use App\Models\Trip\SnapTaskUpgradePay\SnapTaskUpgradePay;
use App\Trip\Code;
use App\Trip\Enums\OrderBusiness;
use App\Trip\Enums\TripTypes;
use App\Trip\Orders\BookOrders\BookOrdersManager;
use App\Trip\Orders\BookOrders\Plane\PriceDetails\ChangePlanePriceDetails;
use App\Trip\Orders\BookOrders\TaskEdit\TaskEditOrder;
use App\Trip\Orders\BookOrders\Train\PriceDetails\ChangePriceDetails;
use App\Trip\Orders\TransferFlag;
use App\Trip\Orders\TripNo;
use App\Trip\Orders\TripOrderState;
use App\Trip\Orders\TripType;
use App\Trip\Repository\BaseRepository;
use App\Trip\Wechat\Pay\PayRes\PayResult;
use App\Trip\Wechat\Pay\WechatPay;
use Closure;
use Exception;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Throwable;

class OrderPayRepository extends BaseRepository implements OrderPayRepositoryInterface
{


    public function __construct(OrderPay $model)
    {
        parent::__construct($model);
    }


    /**
     * 创建火车票支付信息
     * @throws Exception|Throwable
     */
    public function createTrainOrderPayInfo(TrainOrder $order, WechatPay $pay, Channel $channel): OrderPay
    {
        $setPayCache = function (string $order_sn) {
            $cache_key = "createOrderPayInfo:{$order_sn}";
            if (Cache::has($cache_key)) {
                throw new TooManyActionException("您操作的太快了，请稍后重试");
            }
            Cache::put($cache_key, 1, 3);
        };

        $payDetailRepo   = app(OrderPayDetailsRepositoryInterface::class);
        $trainOrdersRepo = app(TrainOrdersRepositoryInterface::class);
        if (!in_array($order->getOrderState(), [
            TripOrderState::ORDER_STATE_WAITING_PAY,
            TripOrderState::ORDER_STATE_CHANGE_WAITING_PAY,
        ])) {
            throw new Exception("无法获取支付信息");
        }

        /**
         * 业务类型
         */
        $business_type = OrderPay::BUSINESS_TYPE_ORDER;
        if ($order->isChangeNew()) {
            $business_type = OrderPay::BUSINESS_TYPE_CHANGE;
        } elseif ($order->isSnapUp()) {
            $business_type = OrderPay::BUSINESS_TYPE_SNAP;
        }
        /**
         * 是否有支付单号
         */
        $pay_type                 = OrderPay::PAY_TYPE_WECHAT;
        $current_order_pay_detail = $payDetailRepo->getTrainOrderPayDetail($order, $business_type);
        $order_pay                = null;
        if ($current_order_pay_detail) {
            $order_pay = $current_order_pay_detail->order_pay;
        }
        $setPayCache($order->getOrderSn());
        /**
         * 验证getReceivable 是否大于0 小于等于0 跳过
         */
        $total_amount = 0;
        $from         = "";
        $to           = "";
        $details      = [];
        $train_code   = "";
        /**
         * 新改签的订单 或普通单程订单
         * 新改签的订单 支付时需要计算新的价格
         */
        $trip_count = 1;
        if ($order->isChangeNew() || $order->getTransferFlag() == TransferFlag::ORDER_TRANSFER_FLAG_NONE) {
            $pay_sn       = $order->getOrderSn();
            $from         = $order->getFromNameUy();
            $train_code   = $order->getTrainCode();
            $to           = $order->getToNameUy();
            $order_amount = $order->getReceivable();
            if ($order->isChangeNew()) {
                $origin_order_info = $trainOrdersRepo->getOrderInfo($order->getOriginOrderSn());
                $passengers        = $order->getPassengers();
                $changePrice       = new ChangePriceDetails($origin_order_info, $passengers->toArray());
                $order_amount      = $changePrice->calcReceivable();
            }
            $total_amount = $order_amount;
            if ($order_pay && $order_pay->getPayAmount() == $total_amount) {
                return $order_pay;
            }
            $details[$order->getOrderSn()] = [
                "user_id"       => $order->getUserId(),
                "trip_id"       => $order->getTripId(),
                "trip_type"     => $order->getTripType(),
                "pay_sn"        => $pay_sn,
                "order_sn"      => $order->getOrderSn(),
                "order_amount"  => $order_amount,
                "separate"      => 0,
                "order_info"    => $order,
                "business_type" => $business_type,
            ];
        } else {
            if ($order_pay) {
                return $order_pay;
            }
            $list   = $trainOrdersRepo->getTripOrders($order);
            $pay_sn = $order->getTripId();
            /**
             * @var TrainOrder $item
             */
            $trip_count = $list?->count() ?: 0;
            foreach ($list as $item) {
                $total_amount += $item->getReceivable();
                if ($item->getTripNo() == TripNo::TRIP_NO_FIRST) {
                    $from = $item->getFromNameUy();
                }
                $to                           = $item->getToNameUy();
                $train_code                   = $item->getTrainCode();
                $details[$item->getOrderSn()] = [
                    "user_id"       => $item->getUserId(),
                    "trip_id"       => $item->getTripId(),
                    "trip_type"     => $order->getTripType(),
                    "pay_sn"        => $pay_sn,
                    "order_sn"      => $item->getOrderSn(),
                    "order_amount"  => $item->getReceivable(),
                    "separate"      => 0,
                    "order_info"    => $item,
                    "business_type" => $business_type,
                ];
            }
        }
        $trip_type_name = __("火车");
        $train_code     = $trip_count > 1 ? __("中转") : $train_code;
        $pay_title      = "{$trip_type_name}/".Str::limit("{$from} -> {$to}", 80, "")."/{$train_code}";
        $data           = [
            "user_id"       => $order->getUserId(),
            "trip_id"       => $order->getTripId(),
            "pay_title"     => $pay_title,
            "pay_sn"        => $pay_sn,
            "pay_type"      => $pay_type,
            "pay_amount"    => $total_amount,
            "pay_state"     => OrderPay::PAY_STATE_WAITING,// 支付状态 0待支付 1已支付 3已取消 2 失败
            "mchid"         => $pay->getMchId(),
            "appid"         => $channel->getAppId(),
            "business_type" => $business_type,
        ];
        $details        = array_values($details);
        DB::transaction(function () use (&$order_pay, $data, $payDetailRepo, $details) {
            if ($order_pay) {
                $order_pay->update([
                    "pay_amount" => $data['pay_amount'],
                ]);

            } else {
                $order_pay = $this->create($data);
            }
            // 生成支付明细
            $payDetailRepo->addMore($order_pay, $details);
        });

        return $order_pay;
    }

    /**
     * 根据支付回调结果 更新业务
     * @throws Exception
     * @throws Throwable
     */
    public function updatePayByPayResult(string $pay_sn, PayResult $result)
    {
        $pay_info = $this->findOneByPaySn($pay_sn);
        if (!$pay_info) {
            $this->markBusinessFailed($result, "支付单数据不存在", null);
            throw new PayInfoNotFoundException($result, "支付单数据不存在", "支付回调-支付单数据不存在：{$pay_sn}");
        }
        // 如果支付成功 直接返回
        if ($pay_info->isPaySuccess()) {
            Log::error("支付回调-成功,业务已处理return：{$pay_sn}");
            return true;
        }

        // 关联的订单
        $relation_order = null;
        // 更具业务类型处理
        $businessType = $pay_info->getBusinessType();
        switch ($businessType) {
            case OrderPay::BUSINESS_TYPE_ORDER:
            case OrderPay::BUSINESS_TYPE_SNAP:
            case OrderPay::BUSINESS_TYPE_CHANGE:
                // 订单已支付
                $closure = function (OrderPay $pay_info, string $pay_sn) use (&$relation_order, $businessType) {
                    /**
                     * @var OrderPayDetail $pay_detail
                     */
                    $pay_details = $pay_info->order_pay_details;
                    foreach ($pay_details as $pay_detail) {
                        if ($pay_detail->getTripType() == TripType::TRIP_TYPE_TRAIN) {
                            $trainOrdersRepo = app(TrainOrdersRepositoryInterface::class);
                            $order_info      = $trainOrdersRepo->getOrderInfo($pay_detail->getOrderSn());
                            $str             = collect($order_info)->toJson(JSON_UNESCAPED_UNICODE);
                            Log::info("火车:{$businessType}:updatePayByPayResult:{$str}");
                            $trainOrdersRepo->orderPaid($order_info, $pay_info);
                            $relation_order = $order_info;
                        } elseif ($pay_detail->getTripType() == TripType::TRIP_TYPE_PLANE) {
                            $planeOrdersRepo = app(PlaneOrderRepositoryInterface::class);
                            $order_info      = $planeOrdersRepo->getOrderInfo($pay_detail->getOrderSn());
                            $str             = collect($order_info)->toJson(JSON_UNESCAPED_UNICODE);
                            Log::info("飞机:{$businessType}:updatePayByPayResult:{$str}");
                            $planeOrdersRepo->orderPaid($order_info, $pay_info);
                            $relation_order = $order_info;
                        }elseif ($pay_detail->getTripType() == TripType::TRIP_TYPE_SCENIC) {
                            //todo 成功并出票
//                            $order_info      = $planeOrdersRepo->getOrderInfo($pay_detail->getOrderSn());
//                            $str             = collect($order_info)->toJson(JSON_UNESCAPED_UNICODE);
//                            Log::info("飞机:{$businessType}:updatePayByPayResult:{$str}");
//                            $planeOrdersRepo->orderPaid($order_info, $pay_info);
//                            $relation_order = $order_info;
                        } else {
                            throw new Exception("支付回调-暂不支持其他业务支付:{$pay_sn}", Code::NOT_SUPPORTED_TRIP_TYPE);
                        }
                    }
                };
                break;
            case OrderPay::BUSINESS_TYPE_TASK_EDIT:
                $closure = function (OrderPay $pay_info) use ($result, &$relation_order) {
                    try {
                        $trainOrdersRepo      = app(TrainOrdersRepositoryInterface::class);
                        $edit_pay             = new SnapTaskEditPay();
                        $edit_pay_info        = $edit_pay->findOneByOrderPay($pay_info);
                        $order_sn             = $edit_pay_info->getOrderSn();
                        $order_info           = $trainOrdersRepo->getOrderInfo($order_sn);
                        $trip_info            = json_decode($edit_pay_info->getTripInfo(), true);
                        $trip_info['user_id'] = $pay_info->getUserId();
                        $trip_info['mobile']  = $order_info->getMobile();
                        $editTaskOrder        = (new BookOrdersManager($trip_info))->getTaskEditOrder();
                        $trainOrdersRepo->updateSnapOrder($order_info, $editTaskOrder, $pay_info);
                        $relation_order = $order_info;
                    } catch (Exception $e) {
                        throw new TrainSnapEditPayErrorException($e->getMessage());
                    }
                };
                break;
            default:
                $this->markBusinessFailed($result, "暂不支持的支付业务", $pay_info);
                Log::error("支付回调-,暂不支持的支付业务,{$pay_sn}");
                throw new NotSupportedPayBusinessException('暂不支持的支付业务');
        }
        $this->dealOrderBusiness($closure, $pay_info, $pay_sn, $result);
        if ($relation_order) {
            // 推送相关订单的状态
            if ($relation_order instanceof PlaneOrder) {
                event(new PlaneOrderStateUpdatedEvent($relation_order));
                ProcessAfterPlaneOrderPaid::dispatch($relation_order, $pay_info);
            }
            if ($relation_order instanceof TrainOrder) {
                event(new TrainOrderStateUpdatedEvent($relation_order));
                ProcessAfterTrainOrderPaid::dispatch($relation_order, $pay_info);
            }
        }
    }

    public function findOneByPaySn(string $pay_sn): OrderPay|null
    {
        return $this->findOneBy(['pay_sn' => $pay_sn]);
    }

    /**
     * 标记该支付需退款
     *
     */
    private function markBusinessFailed(PayResult $result, string $reason, ?OrderPay $pay_info = null): void
    {
        Log::error("支付回调业务处理失败,支付单号:{$result->getOutTradeNo()},原因:{$reason}");
        if ($pay_info) {
            $this->updateOne($pay_info, [
                'pay_state'     => OrderPay::PAY_STATE_SUCCESS_BUSINESS_ERROR,
                'failed_reason' => $reason,
            ]);
            Log::error("支付回调业务处理失败,已标记,支付单号:{$result->getOutTradeNo()},原因:{$reason}");
        }
    }

    public function updateOne(OrderPay $order_pay_info, array $data): bool
    {
        return $this->update($data, $order_pay_info);
    }

    /**
     * @throws Throwable
     * @throws BusinessMustBeRefundException
     */
    private function dealOrderBusiness(Closure $businessClosure, OrderPay $pay_info, string $pay_sn, PayResult $result)
    {
        $isResPaySuccess = false;
        try {
            DB::transaction(function () use (&$isResPaySuccess, $businessClosure, $pay_info, $pay_sn, $result) {
                if ($result->isSuccess()) {
                    $isResPaySuccess = true;
                    $businessClosure($pay_info, $pay_sn);
                    $this->updateOne($pay_info, [
                        'pay_state'   => OrderPay::PAY_STATE_SUCCESS,
                        'trade_sn'    => $result->getTransactionId(),
                        'real_amount' => $result->getPayAmount(),
                        'trade_desc'  => $result->getTradeStateDesc(),
                    ]);
                } else {
                    $this->updateOne($pay_info, [
                        'pay_state'     => OrderPay::PAY_STATE_FAILED,
                        'failed_reason' => $result->getTradeStateDesc(),
                    ]);
                }
            });
        } catch (TrainTicketFailedException $e) {
            if ($isResPaySuccess) {
                $this->markBusinessFailed($result, "订票失败", $pay_info);
                throw new BusinessMustBeRefundException($result, '订票失败', $e->getMessage(), $e->getCode());
            }
        } catch (TrainSnapEditPayErrorException $e) {
            if ($isResPaySuccess) {
                $this->markBusinessFailed($result, $e->getMessage(), $pay_info);
            }
        } catch (PlaneOrderStockNotEnoughException|PlaneTicketFailedException $e) {
            if ($isResPaySuccess) {
                $this->markBusinessFailed($result, $e->getMessage(), $pay_info);
                throw new BusinessMustBeRefundException($result, '订票失败', $e->getMessage(), $e->getCode());
            }
        } catch (Exception $e) {
            Log::error("支付成功后回调,BUSINESS_TYPE: {$pay_info->getBusinessType()} 业务失败,执行退款操作,error:{$e->getMessage()}");
        }
    }

    /**
     * 抢票编辑支付,相同地变更不可重复出现
     * @throws TooManyActionException
     * @throws Exception|Throwable
     */
    public function createTrainSnapTaskEditPay(TrainOrder $order, TaskEditOrder $taskEditOrder, WechatPay $pay, Channel $channel): OrderPay
    {
        $setPayCache = function (string $order_sn) {
            $cache_key = "createTrainSnapTaskEditPayInfo:{$order_sn}";
            if (Cache::has($cache_key)) {
                throw new TooManyActionException("您操作的太快了，请稍后重试");
            }
            Cache::put($cache_key, 1, 5);
        };


        /**
         * 业务类型
         */
        $business_type = OrderPay::BUSINESS_TYPE_TASK_EDIT;

        /**
         * 是否有支付单号
         */
        $pay_type = OrderPay::PAY_TYPE_WECHAT;

        $setPayCache($order->getOrderSn());
        /**
         * 验证getReceivable 是否大于0 小于等于0 跳过
         */
        $details = [];
        /**
         * 新改签的订单 或普通单程订单
         * 新改签的订单 支付时需要计算新的价格
         */
        $pay_sn = generate_order_id(TripTypes::TRAIN, OrderBusiness::PAY);
        $from   = $order->getFromNameUy();
        $to     = $order->getToNameUy();

        $edit_pay            = $taskEditOrder->getEditPay();
        $after_order_amount  = $edit_pay->getAfterOrderAmount();
        $before_order_amount = $edit_pay->getBeforeOrderAmount();
        if ($order->getOrderAmount() != $before_order_amount) {
            Log::error("订单金额发生变化:{$pay_sn},o:{$order->getOrderAmount()},b:{$before_order_amount},a:{$after_order_amount}");
            throw new Exception("订单金额发生变化");
        }

        $need_pay_amount = $edit_pay->getNeedPayAmount();
        $trip_info       = $edit_pay->getTripDataJson();
        $trip_key        = $edit_pay->getTripDataUniqueKey();

        // 获取订单的支付信息
        // 任务关联的支付数据
        $snap_task_edit_pay = new SnapTaskEditPay();
        $edit_pay_info      = $snap_task_edit_pay->findOneByTripKey($trip_key);
        $snap_order_pay     = $edit_pay_info?->order_pay;
        // 如果支付信息已存在 验证支付状态 避免多次编辑
        if ($snap_order_pay) {
            if ($snap_order_pay->isPaySuccess()) {
                throw new Exception("此次编辑已支付,请勿重复编辑");
            }
        }
        $trip_type_name = __("火车");
        $pay_title      = "{$trip_type_name}/".Str::limit("{$from} -> {$to}", 110, "");
        $data           = [
            "user_id"       => $order->getUserId(),
            "trip_id"       => $order->getTripId(),
            "pay_title"     => $pay_title,
            "pay_sn"        => $pay_sn,
            "pay_type"      => $pay_type,
            "pay_amount"    => $need_pay_amount,
            "pay_state"     => OrderPay::PAY_STATE_WAITING,// 支付状态 0待支付 1已支付 3已取消 2 失败
            "mchid"         => $pay->getMchId(),
            "appid"         => $channel->getAppId(),
            "business_type" => $business_type,
        ];

        $edit_pay_data = [
            "task_id"             => $order->getTaskId(),
            "order_sn"            => $order->getOrderSn(),
            "pay_sn"              => $data['pay_sn'],
            "trip_info"           => $trip_info,
            "trip_key"            => $trip_key,
            "before_order_amount" => $before_order_amount,
            "after_order_amount"  => $after_order_amount,
            "pay_amount"          => $need_pay_amount,
        ];
        DB::transaction(function () use (&$snap_order_pay, $data, $edit_pay_data, $snap_task_edit_pay) {
            if (!$snap_order_pay) {
                $snap_order_pay = $this->create($data);
                $snap_task_edit_pay->addPay($snap_order_pay, $edit_pay_data);
            }
        });

        return $snap_order_pay;
    }

    /**
     * 火车票订单退款需支付
     * @param RefundNeedPay $pay
     * @return OrderPay
     */
    public function createTrainOrderRefundNeedPay(RefundNeedPay $pay): OrderPay
    {
        $order_pay = $this->findOneByPaySn($pay->getPaySn());
        if (!$order_pay) {
            $data      = [
                "user_id"       => $pay->getUserId(),
                "trip_id"       => $pay->getTrainOrderInfo()->getTripId(),
                "pay_title"     => $pay->getPayTitle(),
                "pay_sn"        => $pay->getPaySn(),
                "pay_type"      => $pay->getPayType(),
                "pay_amount"    => $pay->getPayAmount(),
                "pay_state"     => OrderPay::PAY_STATE_WAITING,// 支付状态 0待支付 1已支付 3已取消 2 失败
                "mchid"         => $pay->getMchId(),
                "appid"         => $pay->getAppId(),
                "business_type" => OrderPay::BUSINESS_TYPE_REFUND_NEED_PAY,
            ];
            $order_pay = $this->create($data);
        } else {
            // 相同的 trip_key 可能
            $this->updateOne($order_pay, [
                "pay_amount"  => $pay->getPayAmount(),
                "real_amount" => $pay->getReceipts(),
                "pay_state"   => $pay->getPayState(),
            ]);
        }
        return $order_pay;
    }

    /**
     * 火车票抢票加速等级支付
     * @param SnapTaskUpgradePay $pay
     * @return OrderPay
     */
    public function createTrainSnapTaskUpgradePay(SnapTaskUpgradePay $pay): OrderPay
    {
        $order_pay = $this->findOneByPaySn($pay->getPaySn());
        if (!$order_pay) {
            $data      = [
                "user_id"       => $pay->getUserId(),
                "trip_id"       => $pay->getTaskId(),
                "pay_title"     => $pay->getPayTitle(),
                "pay_sn"        => $pay->getPaySn(),
                "pay_type"      => $pay->getPayType(),
                "pay_amount"    => $pay->getPayAmount(),
                "pay_state"     => OrderPay::PAY_STATE_WAITING,// 支付状态 0待支付 1已支付 3已取消 2 失败
                "mchid"         => $pay->getMchId(),
                "appid"         => $pay->getAppId(),
                "business_type" => OrderPay::BUSINESS_TYPE_TASK_UPGRADE_LEVEL,
            ];
            $order_pay = $this->create($data);
        } else {
            // 已存在时更新实际金额
            $this->updateOne($order_pay, [
                "real_amount" => $pay->getReceipts(),
                "pay_state"   => $pay->getPayState(),
            ]);
        }
        return $order_pay;
    }

    /**
     * @param PlaneOrder $order
     * @param WechatPay  $pay
     * @param Channel    $channel
     * @return OrderPay
     * @throws Exception|Throwable
     */
    public function createPlaneOrderPayInfo(PlaneOrder $order, WechatPay $pay, Channel $channel): OrderPay
    {
        if ($order->provider_price_state == 0) {
            throw new Exception("订单价格确认中");
        }
        $setPayCache = function (string $order_sn) {
            $cache_key = "createOrderPayInfo:{$order_sn}";
            if (Cache::has($cache_key)) {
                throw new TooManyActionException("您操作的太快了，请稍后重试");
            }
            Cache::put($cache_key, 1, 3);
        };

        $payDetailRepo   = app(OrderPayDetailsRepositoryInterface::class);
        $planeOrdersRepo = app(PlaneOrderRepositoryInterface::class);
        if (!in_array($order->getOrderState(), [
            TripOrderState::ORDER_STATE_WAITING_PAY,
            TripOrderState::ORDER_STATE_CHANGE_WAITING_PAY,
        ])) {
            throw new Exception("无法获取支付信息");
        }

        /**
         * 业务类型
         */
        $business_type = OrderPay::BUSINESS_TYPE_ORDER;
        if ($order->isChangeNew()) {
            $business_type = OrderPay::BUSINESS_TYPE_CHANGE;
        }
        /**
         * 是否有支付单号
         */
        $pay_type                 = OrderPay::PAY_TYPE_WECHAT;
        $current_order_pay_detail = $payDetailRepo->getPlaneOrderPayDetail($order, $business_type);
        $order_pay                = null;
        if ($current_order_pay_detail) {
            $order_pay = $current_order_pay_detail->order_pay;
        }
        $setPayCache($order->getOrderSn());
        /**
         * 验证getReceivable 是否大于0 小于等于0 跳过
         */
        $total_amount = 0;
        $from         = "";
        $to           = "";
        $details      = [];
        $flight_no    = "";
        /**
         * 新改签的订单 或普通单程订单
         * 新改签的订单 支付时需要计算新的价格
         */
        $trip_count = 1;
        if ($order->isChangeNew() || $order->getTransferFlag() == TransferFlag::ORDER_TRANSFER_FLAG_NONE) {
            $pay_sn       = $order->getOrderSn();
            $from         = $order->getFromNameUy();
            $flight_no    = $order->getFlightNo();
            $to           = $order->getToNameUy();
            $order_amount = $order->getReceivable();
            if ($order->isChangeNew()) {
                $origin_order_info = $planeOrdersRepo->getOrderInfo($order->getOriginOrderSn());
                $passengers        = $order->getPassengers();
                $changePrice       = new ChangePlanePriceDetails($origin_order_info, $passengers->toArray());
                $order_amount      = $changePrice->calcReceivable();
            }
            $total_amount = $order_amount;
            if ($order_pay && $order_pay->getPayAmount() == $total_amount) {
                return $order_pay;
            }
            $details[$order->getOrderSn()] = [
                "user_id"       => $order->getUserId(),
                "trip_id"       => $order->getTripId(),
                "trip_type"     => $order->getTripType(),
                "pay_sn"        => $pay_sn,
                "order_sn"      => $order->getOrderSn(),
                "order_amount"  => $order_amount,
                "separate"      => 0,
                "order_info"    => $order,
                "business_type" => $business_type,
            ];
        } else {
            if ($order_pay) {
                return $order_pay;
            }
            $list   = $planeOrdersRepo->getTripOrders($order);
            $pay_sn = $order->getTripId();
            /**
             * @var PlaneOrder $item
             */
            $trip_count = $list?->count() ?: 0;
            foreach ($list as $item) {
                $total_amount += $item->getReceivable();
                if ($item->getTripNo() == TripNo::TRIP_NO_FIRST) {
                    $from = $item->getFromNameUy();
                }
                $to                           = $item->getToNameUy();
                $flight_no                    = $item->getFlightNo();
                $details[$item->getOrderSn()] = [
                    "user_id"       => $item->getUserId(),
                    "trip_id"       => $item->getTripId(),
                    "trip_type"     => $order->getTripType(),
                    "pay_sn"        => $pay_sn,
                    "order_sn"      => $item->getOrderSn(),
                    "order_amount"  => $item->getReceivable(),
                    "separate"      => 0,
                    "order_info"    => $item,
                    "business_type" => $business_type,
                ];
            }
        }
        $trip_type_name = __("飞机");
        $flight_no      = $trip_count > 1 ? __("中转") : $flight_no;
        $pay_title      = "{$trip_type_name}/".Str::limit("{$from} -> {$to}", 80, "")."/{$flight_no}";
        $data           = [
            "user_id"       => $order->getUserId(),
            "trip_id"       => $order->getTripId(),
            "pay_title"     => $pay_title,
            "pay_sn"        => $pay_sn,
            "pay_type"      => $pay_type,
            "pay_amount"    => $total_amount,
            "pay_state"     => OrderPay::PAY_STATE_WAITING,// 支付状态 0待支付 1已支付 3已取消 2 失败
            "mchid"         => $pay->getMchId(),
            "appid"         => $channel->getAppId(),
            "business_type" => $business_type,
        ];
        $details        = array_values($details);
        DB::transaction(function () use (&$order_pay, $data, $payDetailRepo, $details) {
            if ($order_pay) {
                $order_pay->update([
                    "pay_amount" => $data['pay_amount'],
                ]);

            } else {
                $order_pay = $this->create($data);
            }
            // 生成支付明细
            $payDetailRepo->addMore($order_pay, $details);
        });

        return $order_pay;
    }


    public function createScenicOrderPayInfo(ScenicOrder $order, WechatPay $pay, Channel $channel): OrderPay
    {
        if ($order->provider_price_state == 0) {
            throw new Exception("订单价格确认中");
        }
        $setPayCache = function (string $order_sn) {
            $cache_key = "createOrderPayInfo:{$order_sn}";
            if (Cache::has($cache_key)) {
                throw new TooManyActionException("您操作的太快了，请稍后重试");
            }
            Cache::put($cache_key, 1, 3);
        };

        $payDetailRepo   = app(OrderPayDetailsRepositoryInterface::class);
        if (!in_array($order->order_state, [
            TripOrderState::ORDER_STATE_WAITING_PAY,
            TripOrderState::ORDER_STATE_CHANGE_WAITING_PAY,
        ])) {
            throw new Exception("无法获取支付信息");
        }

        /**
         * 业务类型
         */
        $business_type = OrderPay::BUSINESS_TYPE_ORDER;

        /**
         * 是否有支付单号
         */
        $pay_type                 = OrderPay::PAY_TYPE_WECHAT;
        $current_order_pay_detail = $payDetailRepo->getScenicOrderPayDetail($order, $business_type);
        $order_pay                = null;
        if ($current_order_pay_detail) {
            $order_pay = $current_order_pay_detail->order_pay;
        }

        $setPayCache($order->order_sn);

        if ($order_pay) {
            return $order_pay;
        }
        $total_amount = 0;
        $details      = [];

        $pay_sn = $order->trip_id;
        $order_goods = ScenicOrderGoods::where('order_sn',$order->order_sn)->first();
//        $details[$order_goods->order_sn] = [
//            "user_id"       => $order_goods->user_id,
//            "trip_id"       => $order->trip_id,
//            "trip_type"     => $order->trip_type,
//            "pay_sn"        => $pay_sn,
//            "order_sn"      => $order_goods->order_sn,
//            "order_amount"  => $order_goods->price,
//            "separate"      => 0,
//            "order_info"    => $order_goods,
//            "business_type" => $business_type,
//        ];
        $scenic_goods = ScenicSpotGoods::where('ticket_id',$order_goods->ticket_id)->first();
        $pay_title      = '购买门票';
        if ($scenic_goods instanceof ScenicSpotGoods){
            $pay_title = '购买'.$scenic_goods->ticket_name;
        }
        $data           = [
            "user_id"       => $order->user_id,
            "trip_id"       => $order->trip_id,
            "pay_title"     => $pay_title,
            "pay_sn"        => $pay_sn,
            "pay_type"      => $pay_type,
            "pay_amount"    => $total_amount,
            "pay_state"     => OrderPay::PAY_STATE_WAITING,// 支付状态 0待支付 1已支付 3已取消 2 失败
            "mchid"         => $pay->getMchId(),
            "appid"         => $channel->getAppId(),
            "business_type" => $business_type,
        ];
        $details        = array_values($details);
        DB::transaction(function () use (&$order_pay, $data, $payDetailRepo, $details) {
            if ($order_pay) {
                $order_pay->update([
                    "pay_amount" => $data['pay_amount'],
                ]);

            } else {
                $order_pay = $this->create($data);
            }
            // 生成支付明细
            $payDetailRepo->addMore($order_pay, $details);
        });

        return $order_pay;
    }
}